﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Odbc;
using System.Data.SqlClient;
using System.Threading;
using System.IO;

namespace Btrieve_Retriever
{
    /*
     * This class is in charge of displaying a particular data table to the user from within the program
     * */

    public partial class TableDisplay : Form
    {
        private String tableName;
        private OdbcDataReader reader;
        private int columnCount;
        private int rowCount, currentRow;
        private bool terminateRead = false;
        static AutoResetEvent autoEvent;

        public TableDisplay(String title)
        {
            InitializeComponent();
            this.Text = title;
            tableName = title;
            label1.Text = "Warning: Tables are very large and will take a lot of time to fully load";
            createTable();
        }

        /* Function to read all of the record data in a Btrieve table, 
         * create a data table in the view and name it's coulmns accordingly.
         * */
        private void createTable()
        {
            String query = "SELECT * FROM " + tableName;
            OdbcCommand command = new OdbcCommand(query, Program.myConnection);
            reader = command.ExecuteReader(CommandBehavior.SequentialAccess);

            columnCount = reader.FieldCount;
            dataGridView1.ColumnCount = columnCount;
            dataGridView1.ColumnHeadersVisible = true;

            //Set the name of each view column according to the Btrieve column name.
            for (int i = 0; i < columnCount; i++)
            {
                dataGridView1.Columns[i].Name = (reader.GetName(i));
            }
        }

        /* Function called on button click to start the background worker.
         * */
        private void button1_Click(object sender, EventArgs e)
        {
            progressBar1.Visible = true;
            button1.Visible = false;
            terminateRead = false;
            button2.Visible = true;
            backgroundWorker1.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            populateRow();
        }

        /* Function to copy row data to the view table. It gets the number of rows in the table
         * via a new query and uses the data reader from "createTable()" to get the needed data.
         * It calculates the percentage completed to notify the user via the progress bar.
         * Rows are not added to the view here as this is a separate thread. They are passed on 
         * to the progress report function of the backgroundworker
         * */
        private void populateRow()
        {
            String query2 = "SELECT COUNT(*) FROM " + tableName;
            OdbcCommand command2 = new OdbcCommand(query2, Program.myConnection);
            rowCount = (int)command2.ExecuteScalar();
            currentRow = 0;

            string[] row = new string[columnCount];
            while (!terminateRead)
            {
                if (reader.Read())
                {
                    try
                    {
                        for (int i = 0; i < columnCount; i++)
                        {
                            if (reader != null)
                            {
                                row[i] = reader.GetString(i);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("Read Process interrupted");
                    }
                    currentRow++;
                    double perc = ((double)currentRow / rowCount) * 100.0;
                    int percentageComplete = Convert.ToInt32(perc);

                    autoEvent = new AutoResetEvent(false);
                    Thread newThread = new System.Threading.Thread(delegate()
                    {
                        backgroundWorker1.ReportProgress(percentageComplete, row);
                    });
                    newThread.Start();
                    autoEvent.WaitOne();
                    //Thread.Sleep(200);
                }
            }
        }

        /* Function to display the progress percentage to the user and add rows copied
         * from the Btrieve table to the view.
         * */
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // string array of the data read in the populateRows() function.
            string[] row = (string[])e.UserState;
            progressBar1.Value = e.ProgressPercentage;
            label1.Text = "Loaded " + e.ProgressPercentage + "% (" + currentRow + "\\" + rowCount + ") of the file";
            dataGridView1.Rows.Add(row);

            dataGridView1.Rows[currentRow - 1].HeaderCell.Value = (currentRow).ToString();
            dataGridView1.Refresh();
            autoEvent.Set();
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progressBar1.Visible = false;
            if (terminateRead)
            {
                label1.Text = "Load stopped. Loaded: " + currentRow + " out of " + rowCount + " records";
                terminateRead = false;
            }
            else
            {
                label1.Visible = false;
            }
            reader.Close();
        }


        private void label1_Click(object sender, EventArgs e)
        {
            label1.Visible = false;
        }



        private void Form3_Load(object sender, EventArgs e)
        {

        }



        private void Form3_FormClosed(object sender, FormClosedEventArgs e)
        {
            Console.WriteLine("CLOSED");
            terminateRead = true;
            reader.Close();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (!terminateRead)
            {
                terminateRead = true;
                button2.Text = "OK";
            }
            else
            {
                button2.Visible = false;
                label1.Visible = false;
            }
            reader.Close();
        }

    }
}
